﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Palc.XMPP.Exceptions;
using System.Text.RegularExpressions;

namespace Palc.XMPP
{
    public class JabberIdentifier
    {
        #region public const attributes

        public const int MaximumJabberIdentifierLength = 3071;
        public const int MaximumJabberIdentifierPartLength = 1023;
        public const char NodeSeparator = '@';
        public const char ResourceSeparator = '/';
        public const string SpecialCharactersRegex = "[\"&':<>]"; //check for @ and / not inside test because they are caught by the parser

        #endregion 

        #region private attributes

        private string domain;
        private string resource;
        private string node;

        #endregion

        #region core Jabber Identifier Properties
        /// <summary>
        /// A fully qualified domain name, including subdomains if necessary or an ip address e.g. ipv4 or ipv6
        /// </summary>
        public string Domain
        {
            get
            {
                return this.domain;
            }
            set
            {
                if (value.Length > MaximumJabberIdentifierPartLength)
                    throw new JabberIdentifierException("The JID Domain exceeds the 1023 bytes limit");

                if (value.IndexOf(NodeSeparator) != -1)
                    throw new JabberIdentifierException("Node Separator is not valid inside a Domain");

                if (value.IndexOf(ResourceSeparator) != -1)
                    throw new JabberIdentifierException("Resource Seperator is not valid inside a Domain");

                if (value.Length == 0)
                    throw new JabberIdentifierException("The JID Domain must not be empty");

                this.domain = value;
            }
        }

        /// <summary>
        /// A resoruce is mostly used to identify the chatclient, especially if a user is logging 
        /// in from different locations.
        /// </summary>
        public string Resource
        {
            get
            {
                return this.resource;
            }
            set
            {
                if (value.Length > MaximumJabberIdentifierPartLength)
                    throw new JabberIdentifierException("The JID Resource exceeds the 1023 bytes limit");

                if (value.IndexOf(NodeSeparator) != -1)
                    throw new JabberIdentifierException("The JID Resource must not contain a Node-part");

                if (value.IndexOf(ResourceSeparator) != -1)
                    throw new JabberIdentifierException("The JID Resource must not contain further Resource separators");

                this.resource = value;
            }
        }

        /// <summary>
        /// The node identifiere represents a client or any other service which uses the current server.
        /// </summary>
        public string Node
        {
            get
            {
                return this.node;
            }
            set
            {
                if (value.IndexOf(NodeSeparator) != -1)
                    throw new JabberIdentifierException("The JID Node must not contain further Node separators");

                if (value.IndexOf(ResourceSeparator) != -1)
                    throw new JabberIdentifierException("The JID Node must not contain Resource separators");

                if (value.Length > MaximumJabberIdentifierPartLength)
                    throw new JabberIdentifierException("The JID Node exceeds the 1023 bytes limit");

                this.node = value;
            }
        }

        /// <summary>
        /// The complete JID in the form node@domain/resource
        /// </summary>
        public string FullAddress
        {
            get
            {
                return this.node + NodeSeparator + this.domain + ResourceSeparator + this.resource;
            }
            set
            {
                string tempDomain;
                int indexOfNodeSeparator = value.IndexOf(NodeSeparator);
                int indexOfResourceSeparator = value.IndexOf(ResourceSeparator);

                Regex specialchars = new Regex(SpecialCharactersRegex);
                if (specialchars.IsMatch(value))
                    throw new JabberIdentifierException("Invalid characters found");


                // Test the String
                if (value.Length > MaximumJabberIdentifierLength)
                    throw new JabberIdentifierException("The JID exceeds the 3071 bytes limit");

                if (indexOfResourceSeparator != -1)
                {
                    if (indexOfNodeSeparator > indexOfResourceSeparator)
                    {
                        throw new JabberIdentifierException("The Sepearators were mixed up");
                    }
                }

                // Parse the Node
                if (indexOfNodeSeparator != -1)
                {
                    Node = value.Substring(0, indexOfNodeSeparator);
                }

                // Parse the Resource
                if (indexOfResourceSeparator != -1)
                {
                    Resource = value.Substring(indexOfResourceSeparator + 1);
                }

                // Parste the Domain
                tempDomain = value;

                if (indexOfResourceSeparator != -1 && indexOfNodeSeparator != -1)
                {
                    tempDomain = value.Substring(indexOfNodeSeparator + 1, indexOfResourceSeparator - (indexOfNodeSeparator + 1));
                }
                else if (indexOfResourceSeparator == -1 && indexOfNodeSeparator != -1)
                {
                    tempDomain = value.Substring(indexOfNodeSeparator + 1);
                }
                else if (indexOfResourceSeparator != -1 && indexOfNodeSeparator == -1)
                {
                    tempDomain = value.Substring(0, indexOfResourceSeparator - 1);
                }
                else
                {
                    //nothing to do because tempDomain is ok
                }

                Domain = tempDomain;

            }
        }
        #endregion

    }
}
